﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;

using System.Xml;

namespace SearchPicture
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        #region texture
        class anhxam
        {
            public void Gray(Bitmap bmpInput)
            {
                // Lock the bitmap's bits.  
                Rectangle rtg = new Rectangle(0, 0, bmpInput.Width, bmpInput.Height);
                BitmapData bmpData = bmpInput.LockBits(rtg, ImageLockMode.ReadWrite, bmpInput.PixelFormat);

                // Get the address of the first line.
                IntPtr ptr = bmpData.Scan0;

                // Declare an array to hold the bytes of the bitmap.
                // This code is specific to a bitmap with 24 bits per pixels.
                int bytes = bmpInput.Width * bmpInput.Height * 3;
                byte[] rgbValues = new byte[bytes];

                // Copy the RGB values into the array.
                System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

                // Gray transform 
                int GrayLevel;
                for (int counter = 0; counter < rgbValues.Length; counter += 3)
                {
                    GrayLevel = (rgbValues[counter + 0] + rgbValues[counter + 1] + rgbValues[counter + 2]) / 3;
                    rgbValues[counter] = rgbValues[counter + 1] = rgbValues[counter + 2] = (byte)GrayLevel;
                }

                // Copy the RGB values back to the bitmap
                System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);

                bmpInput.UnlockBits(bmpData);
            }

            public double Mean(byte[] his)
            {
                double kq = 0;
                for (int i = 0; i < 256; i++) kq = kq + i * his[i];
                return kq;
            }
            public double Variance(byte[] his)
            {
                double kq = 0;
                double _Mean = Mean(his);
                for (int i = 0; i < 256; i++) kq = kq + Math.Pow(i - _Mean, 2) * his[i];
                return kq;
            }
            public double Skewness(byte[] his)
            {
                double kq = 0;
                double _Mean = Mean(his);
                double _Variance = Math.Sqrt(Variance(his));
                for (int i = 0; i < 256; i++) kq = kq + Math.Pow(i - _Mean, 3) * his[i];
                return (kq / Math.Pow(_Variance, 3));
            }
            public double Kurtosis(byte[] his)
            {
                double kq = 0;
                double _Mean = Mean(his);
                for (int i = 0; i < 256; i++) kq = kq + Math.Pow(i - _Mean, 4) * his[i];
                return (kq / 4 - 3);
            }
            public double Entropy(byte[] his)
            {
                double kq = 0;
                for (int i = 0; i < 256; i++)
                    if (his[i] != 0) kq = kq - his[i] * Math.Log(his[i], Math.E);
                return (kq);
            }
        }

        private Bitmap ToGray(Bitmap bm)//chuyen sang anh nhi phan
        {
            Bitmap bitmap = new Bitmap(bm);
            try
            {
                int x, y;
                Color c;
                Byte gray;
                for (y = 0; y < bm.Height - 1; y++)
                {
                    for (x = 0; x < bm.Width - 1; x++)
                    {
                        c = bm.GetPixel(x, y);
                        gray = Convert.ToByte(c.R * 0.287 + c.G * 0.599 + c.B * 0.114);
                        bitmap.SetPixel(x, y, Color.FromArgb(gray, gray, gray));
                    }
                }


            }
            catch (Exception ex)
            {
                MessageBox.Show("error:" + ex);
            }
            return bitmap;

        }

        public Double[] TrichXuatTexture(Bitmap bmp)
        {
            Bitmap bmG;
            Double[] kq = new Double[5];

            anhxam anh = new anhxam();//tao mot doi tuong anhxam

            bmG = ToGray(bmp);

            //Tinh H[x]
            int x, y;
            byte[] Histo = new byte[256];
            for (y = 0; y < bmG.Height - 1; y++)
            {
                for (x = 0; x < bmG.Width - 1; x++)
                    Histo[bmG.GetPixel(x, y).R] += 1;
            }


            kq[0] = anh.Mean(Histo);
            kq[1] = anh.Variance(Histo);
            kq[2] = anh.Skewness(Histo);
            kq[3] = anh.Kurtosis(Histo);
            kq[4] = anh.Entropy(Histo);
            return kq;

        }

        private double Euclit(double[] P, double[] Y)//tinh Euclit
        {
            double tong1 = 0;
            //double _Mean = Mean(his);
            for (int i = 0; i < 5; i++)
            {
                //kq += P[i] * Y[i];
                tong1 += Math.Pow(P[i] - Y[i], 2);
                //tong2 += Math.Pow(Y[i], 2);
            }
            return Math.Sqrt(tong1);//kq / (Math.Sqrt(tong1) * Math.Sqrt(tong2));
        }

        public Bitmap[] searchTexture(Double[] texture)
        {

            //doc du lieu trong xml
            XmlDocument data = new XmlDocument();
            data.Load("texture.xml");
            XmlNodeList xnList = data.SelectNodes("/DATA/TEXTURE");

            int countNode = xnList.Count;

            Double[] tuongDong = new Double[countNode];
            String[] FileName = new String[countNode];
            int i = 0;

            foreach (XmlNode xn in xnList)
            {
                String[] dbStr = xn.InnerText.Split(' ');
                Double[] dbDouble = new Double[5];
                for (int n = 0; n < 5; n++)
                {
                    dbDouble[n] = Double.Parse(dbStr[n]);
                }
                tuongDong[i] = Euclit(texture, dbDouble);//lu do tuong dong cua tat ca cac anh so voi anh dc search
                i++;
            }
            Double min = tuongDong[i - 1];
            for (i = 0; i < countNode; i++)
            {
                if (tuongDong[i] < min)
                    min = tuongDong[i];
            }

            //xap xep tinh tuong dong
            int[] idTuongDong = new int[countNode];
            int k = 0, j;
            for (j = 0; j < i; j++)
            {
                if (min == tuongDong[j])//tim id co diem tuong dong thap nhat;
                {
                    idTuongDong[k] = j;//luu nhung id co diem tuong dong thap nhat=min
                    k++;
                }
            }

            int id;
            j = 0;

            for (k = 0; k < xnList.Count; k++)///=>Lay ra duong dan file
            {
                // Set for each element in the nodelist to XmlNode
                XmlNode node = xnList[k];

                // Get the node's attributes
                XmlAttributeCollection attCol = node.Attributes;

                // Print them for testing               
                id = int.Parse(attCol[0].Value.ToString());

                //
                if (isIntInArray(idTuongDong, id))
                {
                    FileName[j] = attCol[1].Value;
                    j++;
                }

            }
            //return FileName;
            Bitmap[] imageReturn = new Bitmap[4];
            try
            {
                int h = 0;
                foreach (String filename in FileName)//
                    if (filename != null && h < 4)
                    {
                        Bitmap returnImage = new Bitmap(filename);
                        imageReturn[h] = resizeImage(returnImage, 150, 150);
                        h++;
                    }

                //pic_finish.Image = imageReturn[3];
                //pic_finish2.Image = imageReturn[1];
                //pic_finish3.Image = imageReturn[2];
                //pic_finish4.Image = imageReturn[3];
                //MessageBox.Show(texture[0].ToString() + " : " + texture[2].ToString() + " : " + texture[3].ToString() + " : " + texture[4].ToString());
            }
            catch (Exception ex)
            {
                MessageBox.Show("" + ex);
            }
            return imageReturn;
        }



        #endregion

        #region color
        public Image collectAttributesImage(Image picture1, String fileImage)
        {
            int[, ,] bin_Color = new int[18, 3, 3];
            int H, S, V;
            int[] BinColor = new int[162];


            Bitmap bmp = new Bitmap(xuLyAnh(picture1));

            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    Color color_Pixel = bmp.GetPixel(i, j);
                    float pixI = color_Pixel.GetBrightness();

                    H = Convert.ToInt32(Math.Round(color_Pixel.GetHue() / 20));
                    S = Convert.ToInt32(Math.Round(color_Pixel.GetSaturation() / 0.3));
                    V = Convert.ToInt32(Math.Round(color_Pixel.GetBrightness() / 0.3));
                    if (S >= 2)
                        S = 2;
                    if (V >= 2)
                        V = 2;
                    if (H >= 17)
                        H = 17;

                    bin_Color[H, S, V] += 1;

                }
            }
            pro_xuLi.Value = 40;
            int n = 0;
            for (int i = 0; i < 18; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    for (int k = 0; k < 3; k++)
                    {
                        BinColor[n] = bin_Color[i, j, k];
                        n++;
                    }
                }
            }

            if (appendToXML(BinColor, fileImage))
            {
                pro_xuLi.Value = 100;
                pro_xuLi.Visible = false;
            }
            else
            {
                MessageBox.Show("Not Saved");
            }

            return bmp;
        }

        public String TrichXuatColor(Image picture1)
        {
            int[, ,] bin_Color = new int[18, 3, 3];
            int H, S, V;
            int[] BinColor = new int[162];


            Bitmap bmp = new Bitmap(xuLyAnh(picture1));

            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    Color color_Pixel = bmp.GetPixel(i, j);
                    float pixI = color_Pixel.GetBrightness();

                    H = Convert.ToInt32(Math.Round(color_Pixel.GetHue() / 20));
                    S = Convert.ToInt32(Math.Round(color_Pixel.GetSaturation() / 0.3));
                    V = Convert.ToInt32(Math.Round(color_Pixel.GetBrightness() / 0.3));
                    if (S >= 2)
                        S = 2;
                    if (V >= 2)
                        V = 2;
                    if (H >= 17)
                        H = 17;

                    bin_Color[H, S, V] += 1;

                }
            }
            pro_xuLi.Value = 40;
            int n = 0;
            for (int i = 0; i < 18; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    for (int k = 0; k < 3; k++)
                    {
                        BinColor[n] = bin_Color[i, j, k];
                        n++;
                    }
                }
            }

            pro_xuLi.Value = 50;
            String str = "";

            foreach (int i in BinColor)
            {
                str += i.ToString() + " ";
            }
            pro_xuLi.Value = 60;

            return str;
        }

        public bool isIntInArray(int[] strArray, int key)
        {

            if (strArray.Contains(key))
                return true;
            return false;
        }

        public Image xuLyAnh(Image picture1)
        {
            Bitmap bmp = new Bitmap(picture1);
            Byte gray;
            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    Color color_Pixel = bmp.GetPixel(i, j);
                    float pixI = color_Pixel.GetBrightness();
                    if (pixI < 0.3)
                    {
                        bmp.SetPixel(i, j, Color.Black);
                    }

                    float pixS = color_Pixel.GetSaturation();
                    if (pixS < 0.08)
                    {
                        gray = Convert.ToByte(color_Pixel.R * 0.287 + color_Pixel.G * 0.599 + color_Pixel.B * 0.114);
                        bmp.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
                    }
                }
            }
            return bmp;

        }

        public Bitmap resizeImage(Image img, int width, int height)
        {
            Bitmap b = new Bitmap(width, height);
            Graphics g = Graphics.FromImage((Image)b);

            g.DrawImage(img, 0, 0, width, height);
            g.Dispose();

            return b;
        }

        private Boolean appendToXML(Array h, String fileImage)
        {
            //write array to xml file
            try
            {
                XmlDocument data = new XmlDocument();
                data.Load("xml.xml");
                String str = "";
                foreach (int el in h)
                {
                    str = str + el.ToString() + " ";
                }
                XmlNode root = data.DocumentElement;
                XmlNodeList xmlNL = data.GetElementsByTagName("HSI");
                int count = xmlNL.Count;
                //Create a new node.
                XmlElement elem = data.CreateElement("HSI");
                elem.InnerText = str;

                elem.SetAttribute("id", count.ToString());
                elem.SetAttribute("FileName", fileImage);

                //Add the node to the document.
                root.AppendChild(elem);

                data.Save("xml.xml");
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }

        }
        
        private int accuracyString(String a, String b)//do do chinh xac cua chuoi nhap vao
        {
            String[] A = a.Split(' ');
            String[] B = b.Split(' ');
            int min = 0, max = 0;

            int interrection = 0, tongA = 0, tongB = 0;
            for (int i = 0; i < 162; i++)
            {
                min = int.Parse(A[i]) < int.Parse(B[i]) ? int.Parse(A[i]) : int.Parse(B[i]);
                interrection += min;
                tongA += int.Parse(A[i]);
                tongB += int.Parse(B[i]);
            }
            Double Match;
            max = tongA > tongB ? tongA : tongB;

            Match = 100 * interrection / max;
            Match = Math.Round(Match);
            return (int)Match;

        }

        public Bitmap[] searchColor(String str)
        {
            //doc du lieu trong xml
            XmlDocument data = new XmlDocument();
            data.Load("xml.xml");

            XmlNodeList xnList = data.SelectNodes("/DATA/HSI");
            String hsi = "";
            int id=0;
            String[] FileName = new String[100];
            //String str = txt_input.Text;
            int i = 0,j = 0;
            int[] right=new int[100];
            
            foreach (XmlNode xn in xnList)
            {
                hsi = xn.InnerText;
                if (accuracyString(str, hsi) > 70)//so sanh du lieu//chô này là % giong nhau
                {
                    right[j] = i;
                    j++;
                }
                i++; 
                         
            }
            j=0;
            for (int k = 0; k < xnList.Count; k++)
            {
                // Set for each element in the nodelist to XmlNode
                XmlNode node = xnList[k];

                // Get the node's attributes
                XmlAttributeCollection attCol = node.Attributes;

                // Print them for testing               
                id = int.Parse(attCol[0].Value.ToString());

                //
                if(isIntInArray(right,id)){
                    FileName[j] = attCol[1].Value;
                    j++;
                }
                
            }
            //return FileName;
            Bitmap[] imageReturn = new Bitmap[4];
            try
            {
                pro_xuLi.Value = 100;
                
                int h = 0;
                foreach (String filename in FileName)//cho này nhé.
                    if (filename != null && h < 4)
                    {
                        Bitmap returnImage = new Bitmap(filename);
                        imageReturn[h] = resizeImage(returnImage, 150, 150);
                        h++;
                    }
            }
            catch (Exception ex)
            {
                MessageBox.Show("" + ex);
            }
            return imageReturn;

        }
        #endregion
        private void btu_search_Click(object sender, EventArgs e)
        {
            //String str="";
            Double[] texture = new Double[5];
            Bitmap bmp = new Bitmap(pic_source.Image);
            //str = TrichXuatColor(bmp).ToString();
            Bitmap[] bmp2=new Bitmap[4];
            //bmp2 = searchColor(str);

            texture = TrichXuatTexture(bmp);
            bmp2 = searchTexture(texture);

            pic_finish1.Image = bmp2[0];
            pic_finish2.Image = bmp2[1];
            pic_finish3.Image = bmp2[2];
            pic_finish4.Image = bmp2[3];

            #region abc
            ////doc du lieu trong xml
            //XmlDocument data = new XmlDocument();
            //data.Load("xml.xml");

            //XmlNodeList xnList = data.SelectNodes("/DATA/HSI");
            //String hsi = "";
            //int id=0;
            //String[] FileName = new String[100];
            ////String str = txt_input.Text;
            //int i = 0,j = 0;
            //int[] right=new int[100];
            
            //foreach (XmlNode xn in xnList)
            //{
            //    hsi = xn.InnerText;
            //    if (accuracyString(str, hsi) > 70)//so sanh du lieu//chô này là % giong nhau
            //    {
            //        right[j] = i;
            //        j++;
            //    }
            //    i++; 
                         
            //}
            //j=0;
            //for (int k = 0; k < xnList.Count; k++)
            //{
            //    // Set for each element in the nodelist to XmlNode
            //    XmlNode node = xnList[k];

            //    // Get the node's attributes
            //    XmlAttributeCollection attCol = node.Attributes;

            //    // Print them for testing               
            //    id = int.Parse(attCol[0].Value.ToString());

            //    //
            //    if(isIntInArray(right,id)){
            //        FileName[j] = attCol[1].Value;
            //        j++;
            //    }
                
            //}
            ////return FileName;
            //try
            //{
            //    pro_xuLi.Value = 100;
            //    Bitmap[] imageReturn = new Bitmap[4];
            //    int h = 0;
            //    foreach (String filename in FileName)//cho này nhé.
            //        if (filename != null && h < 4)
            //        {
            //            Bitmap returnImage = new Bitmap(filename);
            //            imageReturn[h] = resizeImage(returnImage, 150, 150);
            //            h++;
            //        }

            //    pic_finish1.Image = imageReturn[0];
            //    pic_finish2.Image = imageReturn[1];
            //    pic_finish3.Image = imageReturn[2];
            //    pic_finish4.Image = imageReturn[3];
            //}
            ////int option=1;
            ////if(rad_texture.Checked)
            ////    option=1;
            ////if(rad_color.Checked){
            ////    option=2;
            ////}
            ////    if (rad_bot.Checked)
            ////{
            ////     option=3;
            ////}
            ////switch(option)
            ////{
            ////    case 1:
            ////        //
            ////        break;

            ////    case 2:
            ////        //
            ////        break;

            ////    case 3:
            ////        //
            ////        break;

            ////    default:
            ////        break;
            ////}            
            //catch (Exception ex)
            //{
            //    MessageBox.Show(""+ex);
            //}
            #endregion
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void pic_source_Click(object sender, EventArgs e)
        {
            //String str;
            OpenFileDialog openFile = new OpenFileDialog();
            openFile.Filter = "Images (*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*";
            openFile.Title = "Select a nice picture ^^ ";
            openFile.Multiselect = false;
            if (openFile.ShowDialog() == DialogResult.OK)
            {
                Bitmap bmp = new Bitmap(openFile.FileName);
                pro_xuLi.Visible = true;
                Bitmap bmp2 = resizeImage(bmp, 256, 256);
                pic_source.Image = bmp2;
                pro_xuLi.Value = 25;
                //str = searchImage(bmp2).ToString();
            }

            pro_xuLi.Value = 100;
            pro_xuLi.Visible = false;
        }

        private void authorToolStripMenuItem_Click(object sender, EventArgs e)
        {            
            ColectionImages f2 = new ColectionImages();
            f2.Show();
        }
    }
}
